package cz.uvn.orthopedy.client.ui.controller;

import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.CheckBox;
import com.google.gwt.user.client.ui.DialogBox;
import com.google.gwt.user.client.ui.FlexTable;
import com.google.gwt.user.client.ui.HTML;
import com.google.gwt.user.client.ui.HorizontalPanel;
import com.google.gwt.user.client.ui.ListBox;
import com.google.gwt.user.client.ui.Panel;
import com.google.gwt.user.client.ui.TextBox;
import com.google.gwt.user.client.ui.VerticalPanel;

import cz.uvn.orthopedy.client.ApplicationController;
import cz.uvn.orthopedy.client.entity.Insurance;
import cz.uvn.orthopedy.client.entity.Patient;
import cz.uvn.orthopedy.client.ui.UIUtils;

public class PatientsController implements PanelController, ClickHandler {

	public static final String[] TABLE_HEADER = {"Name", "Surname", "Rodne Cislo",
						"Insurance", "Address", "Phone", "Email", "Work Absence",
						"Nadstandard", "Edit", "Remove"}; 

	private ApplicationController controller;
	
	private VerticalPanel panel;
	private FlexTable table;
	private Button addButton;

	public PatientsController(ApplicationController controller) {
		this.controller = controller;
		initUI();
	}

	private void initUI() {
		panel = new VerticalPanel();
		panel.setHorizontalAlignment(VerticalPanel.ALIGN_RIGHT);

		table = new FlexTable();
		table.addStyleName("table");
		initTable(0);
		panel.add(table);
		
		addButton = new Button("Add...");
		addButton.addClickHandler(this);
		panel.add(addButton);
	}

	@Override
	public Panel getView() {
		return panel;
	}
	
	@Override
	public void refresh() {
		load();
	}

	@Override
	public void onClick(ClickEvent event) {
		Object source = event.getSource();
		if (source == addButton) {
			showEditDialog(null);
		}
	}
	
	private void initTable(int rows) {
		table.clear(true);
		table.setSize(String.valueOf(TABLE_HEADER.length), String.valueOf(rows + 1));
		table.setCellPadding(TABLE_HEADER.length);
		for (int i = 0; i < TABLE_HEADER.length; i++) {
			table.setText(0, i, TABLE_HEADER[i]);
		}
		table.getRowFormatter().addStyleName(0, "tableHeader");
	}
	
	private void displayPatients(final Patient[] patients) {
		initTable(patients.length);
		for (int i = 0; i < patients.length; i++) {
			final Patient patient = patients[i];
			final Insurance insurance = controller.getInsuranceByID(patient.getInsuranceID());

			table.setText(i + 1, 0, patient.getName());
			table.setText(i + 1, 1, patient.getSurname());
			table.setText(i + 1, 2, patient.getRodneCislo());
			table.setText(i + 1, 3, insurance != null ? insurance.toString() : "<unknown insurance>");
			table.setText(i + 1, 4, patient.getAddress());
			table.setText(i + 1, 5, patient.getPhoneNumber());
			table.setText(i + 1, 6, patient.getEmail());
			table.setText(i + 1, 7, String.valueOf(patient.isWorkAbsence()));
			table.setText(i + 1, 8, String.valueOf(patient.isNadstandard()));
			
			Button editButton = new Button("...");
			editButton.addClickHandler(new ClickHandler() {
				public void onClick(ClickEvent event) {
					showEditDialog(patient);
				}
			});
			table.setWidget(i + 1, 9, editButton);
			
			Button removeButton = new Button("x");
			removeButton.addClickHandler(new ClickHandler() {
				public void onClick(ClickEvent event) {
					remove(patient);
				}
			});
			table.setWidget(i + 1, 10, removeButton);
		}
	}

	private void showEditDialog(final Patient patient) {
		final DialogBox dialogBox = new DialogBox();
		dialogBox.setText(patient == null ? "Add new Patient" : "Edit Patient");
		dialogBox.setAnimationEnabled(true);
		
		final TextBox nameTextBox = new TextBox();
		final TextBox surnameTextBox = new TextBox();
		final TextBox rcTextBox = new TextBox();
		final ListBox insuranceBox = new ListBox(false);
		for (int i = 0; i < controller.getInsurancesCache().length; i++) {
			insuranceBox.addItem(controller.getInsurancesCache()[i].toString());
		}
		insuranceBox.setVisibleItemCount(1);
		final TextBox addressTextBox = new TextBox();
		final TextBox phoneTextBox = new TextBox();
		final TextBox emailTextBox = new TextBox();
		final CheckBox pnTextBox = new CheckBox();
		final CheckBox nsTextBox = new CheckBox();
		
		if (patient != null) {
			int index = 0;
			for (int i = 0; i < controller.getInsurancesCache().length; i++) {
				if (controller.getInsurancesCache()[i].getId().equals(patient.getInsuranceID())) {
					index = i;
					break;
				}
			}
			nameTextBox.setText(patient.getName());
			surnameTextBox.setText(patient.getSurname());
			rcTextBox.setText(patient.getRodneCislo());
			insuranceBox.setSelectedIndex(index);
			addressTextBox.setText(patient.getAddress());
			phoneTextBox.setText(patient.getPhoneNumber());
			emailTextBox.setText(patient.getEmail());
			pnTextBox.setValue(patient.isWorkAbsence());
			nsTextBox.setValue(patient.isNadstandard());
		}

		final Button okButton = new Button("OK");
		okButton.getElement().setId("dialogButton");
		okButton.addClickHandler(new ClickHandler() {
			@Override
			public void onClick(ClickEvent event) {
				String name = nameTextBox.getText();
				String surname = surnameTextBox.getText();
				String rodneCislo = rcTextBox.getText();
				Long insId = controller.getInsurancesCache()[insuranceBox.getSelectedIndex()].getId();
				String address = addressTextBox.getText();
				String phone = phoneTextBox.getText();
				String email = emailTextBox.getText();
				boolean workAbsence = pnTextBox.getValue();
				boolean nadstandard = nsTextBox.getValue();
				
				if (name.length() < 1) {
					// TODO error label
					Window.alert("Incorrect name!");
					return;
				}
				if (surname.length() < 1) {
					// TODO error label
					Window.alert("Incorrect surname!");
					return;
				}
				if (rodneCislo.length() != 10) {
					// TODO error label
					Window.alert("Incorrect rodne cislo!");
					return;
				}
				if (patient == null) {
					for (Patient pat : controller.getPatientsCache()) {
						if (pat.getRodneCislo().equals(rodneCislo)) {
							Window.alert("Patient with such rodne cislo is already exists!");
							return;
						}
					}
				}
				
				if (patient == null) {
					Patient pat = new Patient();
					pat.setName(name);
					pat.setSurname(surname);
					pat.setRodneCislo(rodneCislo);
					pat.setInsuranceID(insId);
					pat.setAddress(address);
					pat.setPhoneNumber(phone);
					pat.setEmail(email);
					pat.setWorkAbsence(workAbsence);
					pat.setNadstandard(nadstandard);
					edit(pat);
				} else {
					patient.setName(name);
					patient.setSurname(surname);
					patient.setRodneCislo(rodneCislo);
					patient.setInsuranceID(insId);
					patient.setAddress(address);
					patient.setPhoneNumber(phone);
					patient.setEmail(email);
					patient.setWorkAbsence(workAbsence);
					patient.setNadstandard(nadstandard);
					edit(patient);
				}
				dialogBox.hide();
			}
		});

		final Button cancelButton = new Button("Cancel");
		cancelButton.getElement().setId("dialogButton");
		cancelButton.addClickHandler(new ClickHandler() {
			@Override
			public void onClick(ClickEvent event) {
				dialogBox.hide();
			}
		});

		VerticalPanel dialogVPanel = new VerticalPanel();
		dialogVPanel.addStyleName("dialogVPanel");
		dialogVPanel.add(new HTML("<b>Name:</b>"));
		dialogVPanel.add(nameTextBox);
		dialogVPanel.add(new HTML("<br><b>Surname:</b>"));
		dialogVPanel.add(surnameTextBox);
		dialogVPanel.add(new HTML("<br><b>Rodne Cislo:</b>"));
		dialogVPanel.add(rcTextBox);
		dialogVPanel.add(new HTML("<br><b>Insurance:</b>"));
		dialogVPanel.add(insuranceBox);
		dialogVPanel.add(new HTML("<br><b>Address:</b>"));
		dialogVPanel.add(addressTextBox);
		dialogVPanel.add(new HTML("<br><b>Phone:</b>"));
		dialogVPanel.add(phoneTextBox);
		dialogVPanel.add(new HTML("<br><b>Email:</b>"));
		dialogVPanel.add(emailTextBox);
		dialogVPanel.add(new HTML("<br><b>Working Absence:</b>"));
		dialogVPanel.add(pnTextBox);
		dialogVPanel.add(new HTML("<br><b>Nadstandard:</b>"));
		dialogVPanel.add(nsTextBox);

		dialogVPanel.setHorizontalAlignment(VerticalPanel.ALIGN_RIGHT);
		HorizontalPanel dialogHPanel = new HorizontalPanel();
		dialogHPanel.add(okButton);
		dialogHPanel.add(cancelButton);
		dialogVPanel.add(dialogHPanel);
		
		dialogBox.setWidget(dialogVPanel);
		dialogBox.center();
		nameTextBox.setFocus(true);
	}

	private void load() {
		controller.getJournalService().getPatients(new AsyncCallback<Patient[]>() {
			@Override
			public void onSuccess(final Patient[] patients) {
				displayPatients(patients);
			}
			@Override
			public void onFailure(Throwable error) {
				UIUtils.handleError(error);
			}
		});
	}
	
	private void edit(final Patient patient) {
		if (patient.getId() == null) {
			controller.getJournalService().createPatient(patient, new AsyncCallback<Long>() {
				@Override
				public void onSuccess(Long patientID) {
					load();
				}
				@Override
				public void onFailure(Throwable error) {
					UIUtils.handleError(error);
				}
			});
		} else {
			controller.getJournalService().editPatient(patient, new AsyncCallback<Void>() {
				@Override
				public void onSuccess(Void ignore) {
					load();
				}
				@Override
				public void onFailure(Throwable error) {
					UIUtils.handleError(error);
				}
			});
		}
	}

	private void remove(final Patient patient) {
		controller.getJournalService().deletePatient(patient, new AsyncCallback<Void>() {
			@Override
			public void onSuccess(Void ignore) {
				load();
			}
			@Override
			public void onFailure(Throwable error) {
				UIUtils.handleError(error);
			}
		});
	}
	
}
